﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TaskBinding.cs" company="JDML Consulting Ltd.">
//   Copyright 2011 Photon Project - http://photon.codeplex.com
// </copyright>
// <summary>
//   Defines the TaskBinding type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Photon.Threading.EventPattern
{
    using System;
    using System.Diagnostics.CodeAnalysis;

    public class TaskBinding : ITaskBinding
    {
        #region Fields

        private readonly BeginAsyncMethod _begin;
        private readonly EndAsyncMethod _end;
        private readonly bool _isAsync;

        #endregion

        private TaskBinding(BeginAsyncMethod begin, EndAsyncMethod end, bool isAsync)
        {
            _begin = begin;
            _end = end;
            _isAsync = isAsync;
        }

        #region ITaskBinding Members

        public IAsyncResult Begin(AsyncCallback callBack)
        {
            return _begin(callBack, null);
        }

        public void End(IAsyncResult asyncResult)
        {
            _end(asyncResult);
        }

        public bool IsAsync
        {
            get { return _isAsync; }
        }

        #endregion

        public static ITaskBinding FromAsync(BeginAsyncMethod begin, EndAsyncMethod end)
        {
            return new TaskBinding(begin, end, true);
        }

        public static ITaskBinding From(Action action)
        {
            Exception error = null;
            return new TaskBinding(
                (callBack, userState) =>
                    {
                        try
                        {
                            // perform action
                            action();
                        }
                        catch (Exception e)
                        {
                            error = e;
                        }

                        // callback imediately
                        callBack(null);

                        // return result (not used)
                        return null;
                    },
                ar =>
                    {
                        if (error != null)
                        {
                            throw error;
                        }
                    }, false);
        }

        public static ITaskBinding<TReturn> FromAsync<TReturn>(BeginAsyncMethod begin, EndAsyncMethod<TReturn> end)
        {
            return TaskBinding<TReturn>.FromAsync(begin, end);
        }

        public static ITaskBinding<TReturn> From<TReturn>(Func<TReturn> func)
        {
            return TaskBinding<TReturn>.From(func);
        }
    }

    [SuppressMessage("Microsoft.StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass",
        Justification = "Reviewed. Suppression is OK here.")]
    public class TaskBinding<TReturn> : ITaskBinding<TReturn>
    {
        #region Fields

        private readonly BeginAsyncMethod _begin;
        private readonly EndAsyncMethod<TReturn> _end;
        private readonly bool _isAsync;

        #endregion

        private TaskBinding(BeginAsyncMethod begin, EndAsyncMethod<TReturn> end, bool isAsync)
        {
            _begin = begin;
            _end = end;
            _isAsync = isAsync;
        }

        #region ITaskBinding Members

        public IAsyncResult Begin(AsyncCallback callBack)
        {
            return _begin(callBack, null);
        }

        public TReturn End(IAsyncResult asyncResult)
        {
            return _end(asyncResult);
        }

        public bool IsAsync
        {
            get { return _isAsync; }
        }

        #endregion

        public static ITaskBinding<TReturn> FromAsync(BeginAsyncMethod begin, EndAsyncMethod<TReturn> end)
        {
            return new TaskBinding<TReturn>(begin, end, true);
        }

        public static ITaskBinding<TReturn> From(Func<TReturn> func)
        {
            var result = default(TReturn);
            Exception error = null;

            return new TaskBinding<TReturn>(
                (callback, userState) =>
                    {
                        try
                        {
                            // perform action
                            result = func();
                        }
                        catch (Exception e)
                        {
                            error = e;
                        }

                        // callback imediately
                        callback(null);

                        // return result (not used)
                        return null;
                    },
                ar =>
                    {
                        if (error != null)
                        {
                            throw error;
                        }

                        return result;
                    }, false);
        }
    }
}